package com.lagou.server.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.SQLException;

@Configuration
public class DBConnectionPool {

    @Value("${datasource.config.zkpath}")
    private String datasourceConfigZkPath;

    @Value("${datasource.config.zkUrl}")
    private String datasourceConfigZkUrl;

    private static volatile HikariDataSource dataSource;


    @PostConstruct
    public void init(){
        int sessionTimeoutMs = 10000;
        int connectionTimeoutMs = 10000;
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

        CuratorFramework client = CuratorFrameworkFactory
                .builder().connectString(datasourceConfigZkUrl)
                .sessionTimeoutMs(sessionTimeoutMs)
                .connectionTimeoutMs(connectionTimeoutMs)
                .retryPolicy(retryPolicy).build();

        client.start();

        try {
            byte[] datasourceConfig = client.getData().forPath(datasourceConfigZkPath);
            initDataSource(datasourceConfig);

            // 监听
            NodeCache cache = new NodeCache(client, datasourceConfigZkPath);
            cache.start();

            cache.getListenable().addListener(new NodeCacheListener() {
                @Override
                public void nodeChanged() throws Exception {
                    ChildData currentData = cache.getCurrentData();
                    byte[] data = currentData.getData();
                    // 先关闭之前的
                    dataSource.close();
                    initDataSource(data);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    private void initDataSource(byte[] datasourceConfig) throws UnsupportedEncodingException {
        String dsConfig = new String(datasourceConfig, "GBK");
        JSONObject jsonObject = JSON.parseObject(dsConfig);
            /*
            约定使用JSON格式
            {"jdbc.driver":"org.postgresql.Driver",
            "jdbc.url":"jdbc:postgresql://localhost:5432/test",
            "jdbc.username":"postgres",
            "jdbc.password":"wuhuahe91926317"}
             */
        String jdbcDriver = jsonObject.getString("jdbc.driver");
        String jdbcUrl = jsonObject.getString("jdbc.url");
        String username = jsonObject.getString("jdbc.username");
        String password = jsonObject.getString("jdbc.password");
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(jdbcUrl);
        hikariConfig.setDriverClassName(jdbcDriver);
        hikariConfig.setUsername(username);
        hikariConfig.setPassword(password);
        hikariConfig.addDataSourceProperty("cachePrepStmts", "true");
        hikariConfig.addDataSourceProperty("prepStmtCacheSize", "250");
        hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");

        dataSource = new HikariDataSource(hikariConfig);
    }
}
